package cn.szv5.register.server;

import java.util.Map;

/**
 * 应用模块名称<p>
 * 微服务存活状态监控组件<p>
 * Copyright: Copyright (C) 2022 , Inc. All rights reserved. <p>
 * Company: 阿飞工作室<p>
 *
 * @author Carl
 * @since 2022/2/11 21:18
 */
public class ServiceAliveMonitor {

    /**
     * 检查服务实例存活间隔
     */
    private static final long CHECK_ALIVE_INTERVAL = 60 * 1000L;
    private Daemon daemon;

    public ServiceAliveMonitor() {
        daemon = new Daemon();
        //只要设置了这个标志位，就代表这个线程是一个daemon线程，会随着主线程退出而退出
        //非daemon线程，我们一般叫做工作线程
        //如果工作线程(main线程)都结束了，daemon线程是不会阻止jvm进程退出的
        //daemon线程会跟着jvm进程一起退出
        daemon.setDaemon(true);
    }

    /**
     * 启动后台线程
     */
    public void start() {
        daemon.start();
    }

    /**
     * 负责监控微服务存活状态的后台线程
     */
    private class Daemon extends Thread {

        ServiceRegistry registry = ServiceRegistry.getInstance();

        @Override
        public void run() {
            Map<String, Map<String, ServiceInstance>> registryMap = null;
            while (true) {
                try {
                    // 判断是否需要开启自我保护机制
                    SelfProtectionPolicy selfProtectionPolicy = SelfProtectionPolicy.getInstance();
                    if(selfProtectionPolicy.isEnabled()) {
                        Thread.sleep(CHECK_ALIVE_INTERVAL);
                        continue;
                    }

                    registryMap = registry.getRegistry();
                    for (String serviceName : registryMap.keySet()) {
                        Map<String, ServiceInstance> serviceInstanceMap = registryMap.get(serviceName);

                        for (ServiceInstance serviceInstance : serviceInstanceMap.values()) {
                            if (!serviceInstance.isAlive()) {
                                registry.remove(serviceName, serviceInstance);

                                // 更新自我保护机制的阈值
                                synchronized(SelfProtectionPolicy.class) {
                                    selfProtectionPolicy = SelfProtectionPolicy.getInstance();
                                    selfProtectionPolicy.setExpectedHeartbeatRate(selfProtectionPolicy.getExpectedHeartbeatRate() - 2);
                                    selfProtectionPolicy.setExpectedHeartbeatThreshold((long)(selfProtectionPolicy.getExpectedHeartbeatRate()*0.85));
                                }
                            }
                        }

                    }

                    Thread.sleep(CHECK_ALIVE_INTERVAL);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

            }
        }
    }
}
